using DA.AnimGraph;
using OdinSerializer.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;

namespace DA.AnimGraph.Editor {
    internal class ResourceManager {
        Dictionary<AUID, AGA_Resources.Entry> resources;

        public ResourceManager(AGA_Resources source) {
            // 深拷贝一份过来
            resources = source.entries.Where(e => e.resource != null)
                .Select(e => {
                    var newEntry = new AGA_Resources.Entry() {
                        uuid = e.uuid,
                        resource = e.resource,
                        type = e.type,
                        refCount = e.refCount,
                    };
                    return newEntry;
                }).ToDictionary(e => e.uuid);
        }

        /// <summary>
        /// 保存时用
        /// </summary>
        public List<AGA_Resources.Entry> Dump() {
            return resources
                .Where(e => e.Value.refCount > 0 && e.Value.resource != null)
                .Select(e => {
                    var newEntry = new AGA_Resources.Entry() {
                        uuid = e.Value.uuid,
                        resource = e.Value.resource,
                        type = e.Value.type,
                        refCount = e.Value.refCount,
                    };
                    return newEntry;
                }).ToList();
        }
        public Dictionary<AUID, UnityEngine.Object> DumpToDict() {
            var result = new Dictionary<AUID, UnityEngine.Object>(resources.Count);
            resources.Where(e => e.Value.refCount > 0 && e.Value.resource != null)
                .ForEach(e => result.Add(e.Key, e.Value.resource));
            return result;
        }

        public bool GetResource(AUID uuid, out AGA_Resources.Entry outEntry) {
            if (resources.TryGetValue(uuid, out outEntry)) {
                return true;
            }
            outEntry = default;
            return false;
        }

        /// <summary>
        /// 复制节点时增加计数
        /// </summary>
        public bool AddResourceRefCount(AUID uuid) {
            if (resources.TryGetValue(uuid, out var entry)) {
                entry.refCount++;
                resources[uuid] = entry;
                return true;
            } else {
                D.E($"添加资源引用异常，找不到此资源 uuid: {uuid}");
                return false;
            }
        }

        /// <summary>
        /// 批量添加资源
        /// 用于跨文件粘贴
        /// </summary>
        public Dictionary<AUID, AUID> AddResourcesByEntries(List<AGA_Resources.Entry> entries) {
            var queryDict = resources.Values.ToDictionary(x => x.resource);
            var result = new Dictionary<AUID, AUID>(entries.Count); // 旧id, 新id

            foreach (var entry in entries) {
                bool hasKey = queryDict.ContainsKey(entry.resource);
                if (hasKey) {
                    // 检查资源是否已存在，若有则只记录uuid映射
                    result.Add(entry.uuid, queryDict[entry.resource].uuid);
                } else {
                    // 若没有则添加，计数为0
                    // (entries应当不存在重复内容，所以下面key不会重复)
                    var newEntry = entry;
                    newEntry.refCount = 0;
                    resources.Add(newEntry.uuid, newEntry); // 因为是全新的资源，uuid就直接沿用了
                    result.Add(newEntry.uuid, newEntry.uuid); // kv一样也添加，使用时就不用判断了
                }
            }
            return result;
        }

        public AUID AddResource(UnityEngine.Object obj, AGAResourceType type) {
            if (obj == null) {
                return default;
            }
            AUID uuid;
            var pair = resources.SingleOrDefault(p => p.Value.resource == obj);
            if (!pair.Key.isValid) {
                uuid = AUIDGenerator.Gen();
                resources.Add(uuid, new AGA_Resources.Entry() {
                    uuid = uuid,
                    resource = obj,
                    type = type,
                    refCount = 1,
                });
            } else {
                uuid = pair.Key;
                var t = pair.Value;
                t.refCount++;
                resources[pair.Key] = t;
            }
            return uuid;
        }

        public bool TryRemoveResource(AUID uuid) {
            if (resources.TryGetValue(uuid, out var entry)) {
                entry.refCount--;
                if (entry.refCount < 0) {
                    D.E($"移除资源引用异常，引用计数为负，一定是哪里出错了！ uuid: {uuid} resource: {AssetDatabase.GetAssetPath(resources[uuid].resource)}");
                }
                resources[uuid] = entry;
                return true;
            }
            //D.E($"移除资源引用异常，无法找到该引用，一定是哪里出错了！ uuid: {uuid}\n可能的原因：资源被删除");
            return false;
        }

        internal bool HasResource(AUID clipKey) {
            return resources.ContainsKey(clipKey);
        }

        /// <summary>
        /// 对比引用计数
        /// </summary>
        /// <returns>计数是否正确，错误的原数值</returns>
        internal (bool, int) CompareRefCount(AUID key, int refCount) {
            if (resources.TryGetValue(key, out var entry)) {
                if (entry.refCount == refCount) {
                    return (true, refCount);
                } else {
                    var oldValue = entry.refCount;
                    entry.refCount = refCount;
                    resources[key] = entry;
                    return (false, oldValue);
                }
            }
            // throw new Exception($"不应当查询不到资源：{key}");
            return (true, -1);
        }
    }
}
